<#ftl strip_whitespace=true >
package ${daoPackageName!};

import ${entityPackageName}.${name};
import ${entityPackageName}.${objectifyName};
import java.util.List;
import java.util.ArrayList;
import java.util.Map;

import com.google.appengine.api.datastore.QueryResultIterable;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.NotFoundException;
import com.googlecode.objectify.ObjectifyOpts;
import com.googlecode.objectify.helper.DAOBase;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.objectify.ObjectifyService;

import javax.enterprise.context.ApplicationScoped;

import javax.inject.Named;

<#list importedTypes as type>
import ${type};
</#list>

@ApplicationScoped
@Named ("${daoName}")
public class ${objectifyDaoName} extends DAOBase implements ${daoName} {

	private Logger log = LoggerFactory.getLogger(this.getClass());

	public static class DaoOpts extends ObjectifyOpts {
		
		public DaoOpts() {
			setGlobalCache(true);
			setSessionCache(false);
		}

	}

	public ${objectifyDaoName}() {
		super(new DaoOpts());
	}

	public ${name} create${name}(<#list mandatoryAttributeList as attr>${attr.type} ${attr.name}<#if attr_has_next>, </#if></#list>) {
		return new ${objectifyName}(<#list mandatoryAttributeList as attr>${attr.name}<#if attr_has_next>, </#if></#list>);
	}
	
	public ${name} findById(Long id) {
		if (id == null) return null;
		try {
			return (${name}) ofy().get(${objectifyName}.class, id);
		} catch (NotFoundException e) {
			return null;
		}
	}
	
	public List<${name}> findAll() {
		return getInstances(ofy().query(${objectifyName}.class).fetchKeys());
	}
	
	public void store(${name} co) {
		Key<${objectifyName}> key = ofy().put((${objectifyName}) co);
	}
	
	public void store(List<${name}> l) {
		ofy().put(l);
	}
	
	public void delete(${name} co) {
		ofy().delete(co);
	}
	
	<#list attributes as attribute>
		<#if !(attribute.calculatedValue??) && !(attribute.identifier)>
			<#if attribute.unique>
	public ${name} findBy${attribute.nameCapitalized}(${attribute.shortTypeName} val) {
		return getInstance(ofy().query(${objectifyName}.class).filter("${attribute.name}", val).getKey());
	}
	
			<#else>
	public List<${name}> findBy${attribute.nameCapitalized}(${attribute.shortTypeName} val) {
		return getInstances(ofy().query(${objectifyName}.class).filter("${attribute.name}", val).fetchKeys());
	}
	
			</#if>
		</#if>
	
	</#list>
	<#list uniqueConstraints as uc>
	public ${name} findBy<#list uc.attributes as attr>${attr.nameCapitalized}</#list>(<#list uc.attributes as attr>${attr.type} ${attr.name}<#if attr_has_next>, </#if></#list>) {
		return getInstance(ofy().query(${objectifyName}.class)<#list uc.attributes as attr>.filter("${attr.name}", ${attr.name})</#list>.getKey());
	}

	</#list>
	<#list finders as finder>
	public <#if finder.typeMany>List<${name}><#else>${name}</#if> ${finder.name}(<#list finder.finderOperations as fo>${fo.attribute.type} ${fo.paramName}<#if fo_has_next>, </#if></#list><#if finder.typeMany && finder.limited><#if !finder.emptyFinderOperationList>, </#if>int maxRowCount</#if>) {
		<#if finder.typeMany>
		return getInstances(ofy().query(${objectifyName}.class)
			<#list finder.finderOperations as fo>
				.filter("${fo.attribute.name}<#if fo.typeNotEqual> != </#if><#if fo.typeLessThan> < </#if><#if fo.typeGreaterThan> > </#if>", ${fo.paramName})
			</#list>
			<#if finder.ordered>
				<#list finder.orderBys as o>
				.order("<#if o.descending>-</#if>${o.attribute.name}")
				</#list>
			</#if>
			<#if finder.limited>
				.limit(maxRowCount)
			</#if>
				.fetchKeys());
		<#else>
		return getInstance(ofy().query(${objectifyName}.class)
			<#list finder.finderOperations as fo>
				.filter("${fo.attribute.name}", ${fo.paramName})
			</#list>
			<#if finder.ordered>
				<#list finder.orderBys as o>
				.order(<#if o.descending>-</#if>${o.attribute.name})
				</#list>
			</#if>
				.getKey());
		</#if>
	}
	
	</#list>
	
	@PostConstruct
	public void init() {
		ObjectifyService.register(${objectifyName}.class);
		log.info("Class registered: "+${objectifyName}.class.getName());
	}

	protected List<${name}> getInstances(QueryResultIterable<Key<${objectifyName}>> keys) {
		Map<Key<${objectifyName}>, ${objectifyName}> map = ofy().get(keys);
		List<${name}> l = new ArrayList<${name}>();
		for (${objectifyName} t: map.values()) {
			l.add(t);
		}
		return l;
	}
	
	protected ${objectifyName} getInstance(Key<${objectifyName}> key) {
		if (key != null) {
			try {
				return (${objectifyName}) ofy().get(key);
			} catch (NotFoundException e) {
				return null;
			}
		} 
		return null;
	}
	
}